package com.hutra.utils {
	
	/**
	 *
	 * @author hungconcon
	 */
	public class ArrayUtilities {
		
		public function ArrayUtilities() {
		}
		
		/**
		 *
		 * @param	array
		 */
		public static function clearArray(array:Array):void {
			for (var i:int = 0; i < array.length; i++) {
				delete array.splice(i, 1);
			}
			if (array.length > 0) {
				clearArray(array);
			}
		}
		
		/**
		 * Sync keep client data JSON to Object
		 * @param	vo
		 * @param	object
		 * @return
		 */
		public static function synchronizeValueObject(vo:*, object:Object = null):* {
			if (object == null)
				return null;
			for (var key:String in object) {
				try {
					if (object[key] == 'true') {
						vo[key] = true;
					} else if (object[key] == 'false') {
						vo[key] = false;
					} else if (object[key] != undefined || object[key] != '') {
						if (typeof vo[key] == 'boolean') {
							if (object[key] == 'false') {
								vo[key] = false;
							}
							if (object[key] == '0') {
								vo[key] = false;
							}
							if (object[key] == 'true') {
								vo[key] = false;
							}
							if (object[key] == '1') {
								vo[key] = true;
							}
						} else if (typeof vo[key] == 'object') {
							vo[key] = object[key];
						} else if (typeof vo[key] == 'number') {
							vo[key] = Number(object[key]);
						} else {
							vo[key] = String(object[key]);
						}
					} else {
					}
				} catch (ex:Error) {
				}
			}
			return vo;
		}
		
		/**
		 *
		 * @param	lastlist, the list is originality
		 * @param	index
		 * @param	joinlist, the list you want to join
		 * @return
		 */
		public static function joinArray(lastlist:Array, index:int, joinlist:Array):Array {
			if (index == -1 || (index >= lastlist.length)) {
				lastlist = lastlist.concat(joinlist);
			} else if (index == 0) {
				lastlist = joinlist.concat(lastlist);
			} else {
				var a:Array = lastlist.splice(index); //...8,9]
				var b:Array = lastlist.splice(0, index); //[1,2,3,....
				var c:Array = b.concat(joinlist); //[1,2,3,    |4,5,6,7|     ,8,9]
				lastlist = c.concat(a); //[1,2,3,4,5,6,7,8,9]
			}
			return lastlist;
		}
		
		public static function insertObject(array:Array, index:int, value:Object):Array {
			var original:Array;
			if ((index == -1) || (index > array.length)) {
				array.push(value);
				original = array;
			} else if (index == 0) {
				original = [value].concat(array.splice(index));
			} else {
				var a:Array = array.splice(index);
				var b:Array = array.splice(0, index).push(value);
				original = b.concat(a);
			}
			return original;
		}
		
		public static function removeAt(array:Array, index:uint):Array {
			delete array.splice(index, 1);
			return array;
		}
		
		public static function moveObject(list:Array, from:int, to:int):Array {
			// from is the element you wish to move
			// to is the position you want to insert it
			var temp:Array = list.splice(from, 1);
			list.splice(to, 0, temp[0]);
			return list;
		}
		
		public static function swapList(list:Array, from:Number, to:Number):Array {
			var a:Object = list[from];
			var b:Object = list[to];
			list.splice(from, 1, b);
			list.splice(to, 1, a);
			return list;
		}
		
		public static function randomize(a:Array):Array {
			var aCopy:Array = a.concat();
			var aRandomized:Array = new Array();
			var oElement:Object;
			var nRandom:Number;
			for (var i:Number = 0; i < aCopy.length; i++) {
				nRandom = NumberUtilities.random(0, aCopy.length - 1);
				aRandomized.push(aCopy[nRandom]);
				aCopy.splice(nRandom, 1);
				i--;
			}
			return aRandomized;
		}
		
		public static function average(a:Array):Number {
			return sum(a) / a.length;
		}
		
		public static function sum(a:Array):Number {
			var nSum:Number = 0;
			for (var i:Number = 0; i < a.length; i++) {
				if (typeof a[i] == "number") {
					nSum += a[i];
				}
			}
			return nSum;
		}
		
		public static function max(a:Array):Number {
			var aCopy:Array = a.concat();
			aCopy.sort(Array.NUMERIC);
			var nMaximum:Number = Number(aCopy.pop());
			return nMaximum;
		}
		
		public static function min(a:Array):Number {
			var aCopy:Array = a.concat();
			aCopy.sort(Array.NUMERIC);
			var nMinimum:Number = Number(aCopy.shift());
			return nMinimum;
		}
		
		private static function objectEquals(oInstanceA:Object, oInstanceB:Object):Boolean {
			for (var sItem:String in oInstanceA) {
				if (oInstanceA[sItem] is Object) {
					if (!objectEquals(oInstanceA[sItem], oInstanceB[sItem])) {
						return false;
					}
				} else {
					if (oInstanceA[sItem] != oInstanceB[sItem]) {
						return false;
					}
				}
			}
			return true;
		}
		
		public static function equals(aA:Array, aB:Array, bNotOrdered:Boolean, bRecursive:Boolean):Boolean {
			if (aA.length != aB.length) {
				return false;
			}
			var aACopy:Array = aA.concat();
			var aBCopy:Array = aB.concat();
			if (bNotOrdered) {
				aACopy.sort();
				aBCopy.sort();
			}
			for (var i:Number = 0; i < aACopy.length; i++) {
				if (aACopy[i] is Array && bRecursive) {
					if (!equals(aACopy[i], aBCopy[i], bNotOrdered, bRecursive)) {
						return false;
					}
				} else if (aACopy[i] is Object && bRecursive) {
					if (!objectEquals(aACopy[i], aBCopy[i])) {
						return false;
					}
				} else if (aACopy[i] != aBCopy[i]) {
					return false;
				}
			}
			return true;
		}
		
		public static function findMatchIndex(a:Array, oElement:Object, ... rest):Number {
			var nStartingIndex:Number = 0;
			var bPartialMatch:Boolean = false;
			if (typeof rest[0] == "number") {
				nStartingIndex = rest[0];
			} else if (typeof rest[1] == "number") {
				nStartingIndex = rest[1];
			}
			if (typeof rest[0] == "boolean") {
				bPartialMatch = rest[0];
			}
			var bMatch:Boolean = false;
			for (var i:Number = nStartingIndex; i < a.length; i++) {
				if (bPartialMatch) {
					bMatch = (a[i].indexOf(oElement) != -1);
				} else {
					bMatch = (a[i] == oElement);
				}
				if (bMatch) {
					return i;
				}
			}
			return -1;
		}
		
		public static function findLastMatchIndex(a:Array, oElement:Object, oParameter:Object):Number {
			var nStartingIndex:Number = a.length;
			var bPartialMatch:Boolean = false;
			if (typeof arguments[2] == "number") {
				nStartingIndex = arguments[2];
			} else if (typeof arguments[3] == "number") {
				nStartingIndex = arguments[3];
			}
			if (typeof arguments[2] == "boolean") {
				bPartialMatch = arguments[2];
			}
			var bMatch:Boolean = false;
			for (var i:Number = nStartingIndex; i >= 0; i--) {
				if (bPartialMatch) {
					bMatch = (a[i].indexOf(oElement) != -1);
				} else {
					bMatch = (a[i] == oElement);
				}
				if (bMatch) {
					return i;
				}
			}
			return -1;
		}
		
		public static function findMatchIndices(a:Array, oElement:Object, bPartialMatch:Boolean = false):Array {
			var aIndices:Array = new Array();
			var nIndex:Number = findMatchIndex(a, oElement, bPartialMatch);
			while (nIndex != -1) {
				aIndices.push(nIndex);
				nIndex = findMatchIndex(a, oElement, bPartialMatch, nIndex + 1);
			}
			return aIndices;
		}
		
		public static function duplicate(oArray:Object, bRecursive:Boolean = false):Object {
			var oDuplicate:Object;
			if (bRecursive) {
				if (oArray is Array) {
					oDuplicate = new Array();
					for (var i:Number = 0; i < oArray.length; i++) {
						if (oArray[i] is Object) {
							oDuplicate[i] = duplicate(oArray[i]);
						} else {
							oDuplicate[i] = oArray[i];
						}
					}
					return oDuplicate;
				} else {
					oDuplicate = new Object();
					for (var sItem:String in oArray) {
						if (oArray[sItem] is Object && !(oArray[sItem] is String) && !(oArray[sItem] is Boolean) && !(oArray[sItem] is Number)) {
							oDuplicate[sItem] = duplicate(oArray[sItem], bRecursive);
						} else {
							oDuplicate[sItem] = oArray[sItem];
						}
					}
					return oDuplicate;
				}
			} else {
				if (oArray is Array) {
					return oArray.concat();
				} else {
					oDuplicate = new Object();
					for (var sstem:String in oArray) {
						oDuplicate[sstem] = oArray[sstem];
					}
					return oDuplicate;
				}
			}
		}
		
		static public function toString(oArray:Object, nLevel:uint = 0):String {
			var sIndent:String = "";
			for (var i:Number = 0; i < nLevel; i++) {
				sIndent += "\t";
			}
			var sOutput:String = "";
			for (var sItem:String in oArray) {
				if (oArray[sItem] is Object) {
					sOutput = sIndent + "** " + sItem + " **\n" + toString(oArray[sItem], nLevel + 1) + sOutput;
				} else {
					sOutput += sIndent + sItem + ":" + oArray[sItem] + "\n";
				}
			}
			return sOutput;
		}
	}
}